from flask import Flask, request, jsonify
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime, timedelta
from werkzeug.security import generate_password_hash, check_password_hash
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity
import uuid

app = Flask(__name__)
# 修改 CORS 配置，允许所有来源访问（开发环境）
CORS(app, resources={
    r"/*": {  # 允许所有路径
        "origins": "*",  # 允许所有来源
        "methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
        "allow_headers": ["Content-Type", "Authorization"]
    }
})

# 数据库配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///student_habits.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

# JWT配置
app.config['JWT_SECRET_KEY'] = 'your-secret-key'
app.config['JWT_TOKEN_LOCATION'] = ['headers']
app.config['JWT_HEADER_NAME'] = 'Authorization'
app.config['JWT_HEADER_TYPE'] = 'Bearer'
jwt = JWTManager(app)

# 用户模型
class Parent(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password_hash = db.Column(db.String(120), nullable=False)
    children = db.relationship('Child', backref='parent', lazy=True)
    invite_code = db.Column(db.String(8), unique=True)

class Child(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)  # 登录用户名
    password_hash = db.Column(db.String(120), nullable=False)  # 密码哈希
    name = db.Column(db.String(80), nullable=False)  # 显示名称
    age = db.Column(db.Integer)
    grade = db.Column(db.String(20))
    points = db.Column(db.Integer, default=0)
    parent_id = db.Column(db.Integer, db.ForeignKey('parent.id'), nullable=False)
    habits = db.relationship('Habit', backref='child', lazy=True)

class Habit(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    description = db.Column(db.Text)
    suggested_duration = db.Column(db.Integer)  # 建议完成时间（分钟）
    points_reward = db.Column(db.Integer, default=0)
    child_id = db.Column(db.Integer, db.ForeignKey('child.id'), nullable=False)
    records = db.relationship('HabitRecord', backref='habit', lazy=True)

class HabitRecord(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    date = db.Column(db.Date, nullable=False)
    duration = db.Column(db.Integer)  # 实际用时（分钟）
    completed = db.Column(db.Boolean, default=False)
    points_earned = db.Column(db.Integer, default=0)
    habit_id = db.Column(db.Integer, db.ForeignKey('habit.id'), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

# 数据统计相关模型
class Reward(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    description = db.Column(db.Text)
    points = db.Column(db.Integer, nullable=False)
    image = db.Column(db.String(200))

class Exchange(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    child_id = db.Column(db.Integer, db.ForeignKey('child.id'), nullable=False)
    reward_id = db.Column(db.Integer, db.ForeignKey('reward.id'), nullable=False)
    points = db.Column(db.Integer, nullable=False)
    status = db.Column(db.String(20), default='pending')  # pending, completed, cancelled
    exchange_date = db.Column(db.DateTime, default=datetime.utcnow)

# 在所有模型定义之后，创建数据库表之前
# 创建一个初始化管理员账号的函数
def init_db():
    db.drop_all()  # 删除所有表
    db.create_all()  # 创建所有表
    
    # 创建一个系统管理员账号
    admin = Parent(
        username='admin',
        password_hash=generate_password_hash('admin123'),
        invite_code=str(uuid.uuid4())[:8]
    )
    db.session.add(admin)
    db.session.commit()
    
    # 创建测试用家长账号
    parent = Parent(
        username='test_parent',
        password_hash=generate_password_hash('123456')
    )
    db.session.add(parent)
    db.session.commit()
    
    # 创建测试用孩子账号
    child = Child(
        username='test_child',
        password_hash=generate_password_hash('123456'),
        name='测试孩子',
        age=10,
        grade='四年级',
        parent_id=parent.id
    )
    db.session.add(child)
    db.session.commit()

# 初始化数据库
with app.app_context():
    init_db()

# API路由
@app.route('/api/parents', methods=['POST'])
def register_parent():
    data = request.json
    if Parent.query.filter_by(username=data['username']).first():
        return jsonify({'error': '用户名已存在'}), 400
    
    parent = Parent(
        username=data['username'],
        password_hash=generate_password_hash(data['password'])
    )
    db.session.add(parent)
    db.session.commit()
    return jsonify({'message': '注册成功'}), 201

@app.route('/api/children', methods=['POST'])
def add_child():
    data = request.json
    child = Child(
        name=data['name'],
        age=data['age'],
        grade=data['grade'],
        parent_id=data['parent_id']
    )
    db.session.add(child)
    db.session.commit()
    return jsonify({'message': '添加成功', 'id': child.id}), 201

@app.route('/api/habits', methods=['POST'])
@jwt_required()
def create_habit():
    data = request.json
    current_user = get_jwt_identity()
    
    try:
        # 如果是字典（新格式）
        if isinstance(current_user, dict):
            if current_user['role'] == 'child':
                child_id = current_user['id']
            else:
                child_id = data.get('child_id')
        # 如果是数字（旧格式）
        else:
            child_id = data.get('child_id', current_user)
            
        if not child_id:
            return jsonify({'error': '缺少child_id参数'}), 400
        
        habit = Habit(
            name=data['name'],
            description=data.get('description', ''),
            suggested_duration=data.get('suggested_duration', 30),
            points_reward=data.get('points_reward', 10),
            child_id=child_id
        )
        db.session.add(habit)
        db.session.commit()
        
        return jsonify({
            'message': '习惯创建成功',
            'id': habit.id,
            'name': habit.name
        }), 201
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 400

@app.route('/api/records', methods=['POST'])
def record_habit():
    data = request.json
    record = HabitRecord(
        date=datetime.strptime(data['date'], '%Y-%m-%d').date(),
        duration=data['duration'],
        completed=data['completed'],
        points_earned=data['points_earned'],
        habit_id=data['habit_id']
    )
    db.session.add(record)
    
    # 更新积分
    if record.completed:
        habit = Habit.query.get(data['habit_id'])
        child = Child.query.get(habit.child_id)
        child.points += record.points_earned
        db.session.commit()
    
    return jsonify({'message': '记录添加成功', 'id': record.id}), 201

# 获取指定孩子的习惯列表
@app.route('/api/habits/<int:child_id>', methods=['GET'])
def get_habits(child_id):
    habits = Habit.query.filter_by(child_id=child_id).all()
    return jsonify([{
        'id': habit.id,
        'name': habit.name,
        'description': habit.description,
        'suggested_duration': habit.suggested_duration,
        'points_reward': habit.points_reward
    } for habit in habits])

# 获取习惯的记录
@app.route('/api/habits/<int:habit_id>/records', methods=['GET'])
def get_habit_records(habit_id):
    records = HabitRecord.query.filter_by(habit_id=habit_id).order_by(HabitRecord.date.desc()).all()
    return jsonify([{
        'id': record.id,
        'date': record.date.isoformat(),
        'duration': record.duration,
        'completed': record.completed,
        'points_earned': record.points_earned
    } for record in records])

# 获取时间轴数据
@app.route('/api/timeline/<int:child_id>', methods=['GET'])
def get_timeline(child_id):
    date = request.args.get('date')
    records = db.session.query(
        HabitRecord, Habit.name.label('habit_name')
    ).join(Habit).filter(
        Habit.child_id == child_id,
        HabitRecord.date == datetime.strptime(date, '%Y-%m-%d').date()
    ).order_by(HabitRecord.created_at.desc()).all()
    
    return jsonify([{
        'id': record.HabitRecord.id,
        'habit_name': record.habit_name,
        'duration': record.HabitRecord.duration,
        'completed': record.HabitRecord.completed,
        'points_earned': record.HabitRecord.points_earned,
        'created_at': record.HabitRecord.created_at.isoformat()
    } for record in records])

# 获取月度日历数据
@app.route('/api/calendar/<int:child_id>', methods=['GET'])
def get_calendar(child_id):
    year = int(request.args.get('year'))
    month = int(request.args.get('month'))
    
    start_date = datetime(year, month, 1).date()
    if month == 12:
        end_date = datetime(year + 1, 1, 1).date()
    else:
        end_date = datetime(year, month + 1, 1).date()
    
    records = db.session.query(
        HabitRecord, Habit.name.label('habit_name')
    ).join(Habit).filter(
        Habit.child_id == child_id,
        HabitRecord.date >= start_date,
        HabitRecord.date < end_date
    ).all()
    
    calendar_data = {}
    for record in records:
        date_str = record.HabitRecord.date.isoformat()
        if date_str not in calendar_data:
            calendar_data[date_str] = []
        calendar_data[date_str].append({
            'id': record.HabitRecord.id,
            'habit_name': record.habit_name,
            'duration': record.HabitRecord.duration,
            'points_earned': record.HabitRecord.points_earned
        })
    
    return jsonify(calendar_data)

# 获取单日详细记录
@app.route('/api/calendar/<int:child_id>/day', methods=['GET'])
def get_day_records(child_id):
    date = request.args.get('date')
    records = db.session.query(
        HabitRecord, Habit.name.label('habit_name')
    ).join(Habit).filter(
        Habit.child_id == child_id,
        HabitRecord.date == datetime.strptime(date, '%Y-%m-%d').date()
    ).all()
    
    return jsonify([{
        'id': record.HabitRecord.id,
        'habit_name': record.habit_name,
        'duration': record.HabitRecord.duration,
        'points_earned': record.HabitRecord.points_earned
    } for record in records])

# 获取统计数据
@app.route('/api/statistics/<int:child_id>', methods=['GET'])
def get_statistics(child_id):
    time_range = request.args.get('timeRange', 'week')
    
    # 计算时间范围
    today = datetime.now().date()
    if time_range == 'week':
        start_date = today - timedelta(days=today.weekday())
    elif time_range == 'month':
        start_date = today.replace(day=1)
    else:  # year
        start_date = today.replace(month=1, day=1)
    
    # 查询记录
    records = db.session.query(HabitRecord).join(Habit).filter(
        Habit.child_id == child_id,
        HabitRecord.date >= start_date
    ).all()
    
    # 计算统计数据
    total_records = len(records)
    total_duration = sum(r.duration for r in records)
    total_points = sum(r.points_earned for r in records)
    completed_records = len([r for r in records if r.completed])
    completion_rate = round(completed_records / total_records * 100 if total_records > 0 else 0)
    
    # 计算每个习惯的完成情况
    habits = Habit.query.filter_by(child_id=child_id).all()
    habit_stats = []
    for habit in habits:
        habit_records = [r for r in records if r.habit_id == habit.id]
        if habit_records:
            completion_rate = round(
                len([r for r in habit_records if r.completed]) / len(habit_records) * 100
            )
        else:
            completion_rate = 0
        habit_stats.append({
            'id': habit.id,
            'name': habit.name,
            'completionRate': completion_rate
        })
    
    return jsonify({
        'totalRecords': total_records,
        'totalDuration': total_duration,
        'totalPoints': total_points,
        'completionRate': completion_rate,
        'habitStats': habit_stats
    })

# 积分兑换相关API
@app.route('/api/rewards', methods=['GET'])
def get_rewards():
    rewards = Reward.query.all()
    return jsonify([{
        'id': reward.id,
        'name': reward.name,
        'description': reward.description,
        'points': reward.points,
        'image': reward.image
    } for reward in rewards])

@app.route('/api/exchanges', methods=['POST'])
def create_exchange():
    data = request.json
    child = Child.query.get_or_404(data['child_id'])
    reward = Reward.query.get_or_404(data['reward_id'])
    
    if child.points < reward.points:
        return jsonify({'error': '积分不足'}), 400
    
    exchange = Exchange(
        child_id=data['child_id'],
        reward_id=data['reward_id'],
        points=reward.points
    )
    
    child.points -= reward.points
    db.session.add(exchange)
    db.session.commit()
    
    return jsonify({'message': '兑换成功', 'id': exchange.id}), 201

@app.route('/api/exchanges/<int:child_id>', methods=['GET'])
def get_exchanges(child_id):
    exchanges = db.session.query(
        Exchange, Reward.name.label('reward_name')
    ).join(Reward).filter(
        Exchange.child_id == child_id
    ).order_by(Exchange.exchange_date.desc()).all()
    
    return jsonify([{
        'id': exchange.Exchange.id,
        'reward_name': exchange.reward_name,
        'points': exchange.Exchange.points,
        'status': exchange.Exchange.status,
        'exchange_date': exchange.Exchange.exchange_date.isoformat()
    } for exchange in exchanges])

# 登录API
@app.route('/api/auth/login', methods=['POST'])
def login():
    data = request.json
    role = data.get('role', 'parent')  # 默认为家长登录
    
    try:
        if role == 'parent':
            user = Parent.query.filter_by(username=data['username']).first()
        else:
            user = Child.query.filter_by(username=data['username']).first()
        
        if user and check_password_hash(user.password_hash, data['password']):
            # 创建包含用户ID和角色的身份信息
            identity = {
                'id': user.id,
                'role': role,
                'username': user.username
            }
            
            access_token = create_access_token(identity=identity)
            return jsonify({
                'token': access_token,
                'user_id': user.id,
                'role': role,
                'username': user.username
            })
        
        return jsonify({'error': '用户名或密码错误'}), 401
    except Exception as e:
        return jsonify({'error': str(e)}), 400

# 保护需要认证的API
@app.route('/api/children', methods=['GET'])
@jwt_required()
def get_children():
    current_user = get_jwt_identity()
    
    # 获取家长ID
    if isinstance(current_user, dict):
        parent_id = current_user['id']
    else:
        parent_id = current_user
    
    try:
        children = Child.query.filter_by(parent_id=parent_id).all()
        return jsonify([{
            'id': child.id,
            'name': child.name,
            'age': child.age,
            'grade': child.grade,
            'points': child.points,
            'username': child.username
        } for child in children])
    except Exception as e:
        return jsonify({'error': str(e)}), 400

@app.route('/api/test', methods=['GET'])
def test():
    return jsonify({
        'message': 'API is working!',
        'status': 'success'
    })

# 生成邀请码
@app.route('/api/parents/invite-code', methods=['POST'])
@jwt_required()
def generate_invite_code():
    parent_id = get_jwt_identity()
    # 生成唯一的邀请码
    invite_code = str(uuid.uuid4())[:8]
    
    # 保存邀请码
    parent = Parent.query.get(parent_id)
    parent.invite_code = invite_code
    db.session.commit()
    
    return jsonify({
        'invite_code': invite_code
    })

# 孩子注册
@app.route('/api/children/register', methods=['POST'])
def register_child():
    data = request.json
    
    # 检查用户名是否已存在
    if Child.query.filter_by(username=data['username']).first():
        return jsonify({'error': '用户名已存在'}), 400
    
    # 创建孩子账号
    child = Child(
        username=data['username'],
        password_hash=generate_password_hash(data['password']),
        name=data['username'],  # 用户名作为默认名称
        age=data['age'],
        grade=data['grade'],
        parent_id=1  # 默认分配给系统管理员
    )
    
    db.session.add(child)
    db.session.commit()
    
    return jsonify({'message': '注册成功'}), 201

if __name__ == '__main__':
    # 确保使用 0.0.0.0 以允许外部访问
    app.run(host='0.0.0.0', port=5000, debug=True) 